package com.panopset.flywheel;

import static com.panopset.Util.*;

import java.util.Stack;
import java.util.Vector;

/**
 * Let's get organized here. First load all the commands, from all templates,
 * don't add any structure.
 *
 * @author Karl Dinwiddie
 */
class RawCommandLoader {
    private int                     lineCount = 0;
    private final Template          template;
    private final Stack<String>     queue     = new Stack<String>();
    protected final Vector<Command> commands  = new Vector<Command>();

    RawCommandLoader(Template template) {
        assert template != null;
        this.template = template;
    }

    Vector<Command> load() {
        boolean firstTime = true;
        template.sls.reset();
        String line = template.sls.next();
        while (line != null) {
            if (template.flywheel.isStopped())
                return null;
            flushQueue();
            lineCount++;
            if (firstTime) {
                firstTime = false;
            } else {
                loadCommand(new CommandText(template, getReturnChar()));
            }
            if (template.flywheel.isStopped()) {
                log(x("Stopped at line") + COLON + SINGLE_SPACE + lineCount);
                return null;
            }
            process(line);
            line = template.sls.next();
        }
        flushQueue();
        return commands;
    }

    private void flushQueue() {
        while (!queue.isEmpty()) {
            process(queue.pop());
            if (template.flywheel.isStopped())
                return;
        }
    }

    private void loadCommand(Command command) {
        if (template.firstCommand == null) {
            template.firstCommand = command;
        }
        template.lastCommand = command;
        commands.add(command);
    }

    private void process(String line) {
        int openDirectiveLoc = line.indexOf(template.flywheel.openDirective);
        int closeDirectiveLoc = line.indexOf(template.flywheel.closeDirective);
        if (closeDirectiveLoc == -1 || openDirectiveLoc == -1) {
            loadCommand(new CommandText(template, line));
            return;
        }
        if (closeDirectiveLoc < openDirectiveLoc) {
            skipTo(line, openDirectiveLoc);
            return;
        }
        int endOfDirective = closeDirectiveLoc + template.flywheel.closeDirective.length();
        if (openDirectiveLoc == 0) {
            String remainder = line.substring(endOfDirective);
            if (remainder.length() > 0) {
                this.queue.push(remainder);
            }
            loadCommand(new Command.Builder().template(template).source(line,
                    closeDirectiveLoc).construct());
        } else {
            skipTo(line, openDirectiveLoc);
        }
    }

    private void skipTo(String ln, int pos) {
        loadCommand(new CommandText(template, ln.substring(0, pos)));
        this.queue.push(ln.substring(pos));
    }

    /**
     * @param commands
     */
    public static void addStructure(Vector<Command> commands) {
        if (commands == null) return;
        Command prev = null;
        for (Command command : commands) {
            command.prev = prev;
            if (prev != null) {
                prev.next = command;
            }
            prev = command;
        }
    }

}
